package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.domain.InnerMarketDomain;
import com.itheima.stock.pojo.domain.Stock4EvrDayDomain;
import com.itheima.stock.pojo.domain.Stock4MinuteDomain;
import com.itheima.stock.pojo.domain.StockUpdownDomain;
import com.itheima.stock.pojo.vo.StockInfoConfig;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.resp.PageResult;
import com.itheima.stock.vo.resp.R;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 股票服务实现
 */
@Service
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    /**
     * 获取国内最新大盘数据信息
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfo() {
        // 1、获取股票最新交易时间节点（精确到分钟，秒和毫秒设置为0）
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        // TODO mock data 等后续完成股票采集job工程，再将代码删除即可
        curDate = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // 2、获取大盘编码集合
        List<String> mCodes = stockInfoConfig.getInner();
        // 3、调用mapper（Dao层 数据持久层,也有叫mapper层）查询数据
        List<InnerMarketDomain> data = stockMarketIndexInfoMapper.getMarketInfo(curDate, mCodes);
        // 4、封装并响应
        return R.ok(data);
    }

    /**
     * 分页查询最新的股票交易信息
     * @param page 当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockInfoByPage(Integer page, Integer pageSize) {
        // 1、获取股票最新交易时间节点（精确到分钟，秒和毫秒设置为0）
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        // TODO mock data 等后续完成股票采集job工程，再将代码删除即可
        curDate = DateTime.parse("2021-12-28 13:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // 2、设置PageHelper分页参数
        PageHelper.startPage(page, pageSize);
        // 3、调用mapper查询
        List<StockUpdownDomain> pageData = stockRtInfoMapper.getStockInfoByTime(curDate);
        // 4、组装pageResult对象
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(pageData);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        return R.ok(pageResult);
    }

    /**
     * 统计最新股票交易日内每分钟的涨跌停的股票数量
     * @return
     */
    @Override
    public R<Map<String, List>> getStockUpDownCount() {
        // 1、获取股票最新交易时间节点（截止时间）
        DateTime curDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // TODO mock data 等后续完成股票采集job工程，再将代码删除即可
        curDate = DateTime.parse("2021-12-28 13:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = curDate.toDate();
        // 2、获取最新交易时间节点对应的开盘时间
        Date startTime = DateTimeUtil.getOpenDate(curDate).toDate();
        // 3、统计涨停数据
        List<Map> upList = stockRtInfoMapper.getStockUpDownCount(startTime, endDate, 1);
        // 4、统计跌停数据
        List<Map> downList = stockRtInfoMapper.getStockUpDownCount(startTime, endDate, 0);
        // 5、组装数据
        HashMap<String, List> info = new HashMap<>();
        info.put("upList", upList);
        info.put("downList", downList);
        // 响应数据
        return R.ok(info);
    }

    /**
     * 导出指定页码的最新股票信息
     * @param page 当前页
     * @param pageSize 每页大小
     * @param response
     */
    @Override
    public void exportStockUpDownInfo(Integer page, Integer pageSize, HttpServletResponse response) {
        try {
            // 1、获取分页数据
            R<PageResult<StockUpdownDomain>> r = this.getStockInfoByPage(page, pageSize);
            List<StockUpdownDomain> rows = r.getData().getRows();
            // 2、将数据导出到excel中
            //设置响应excel文件格式类型,设置响应数据的编码格式
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //3.设置默认的文件名称
            String fileName = null;
            fileName = URLEncoder.encode("股票信息表", "UTF-8");
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //4.响应excel流
            EasyExcel
                    .write(response.getOutputStream(),StockUpdownDomain.class)
                    .sheet("股票信息")
                    .doWrite(rows);
        } catch (IOException e) {
            log.info("当前导出数据异常，当前页：{},每页大小：{},异常信息：{}",page,pageSize,e.getMessage());
        }
    }

    /**
     * 功能描述：统计国内A股大盘T日和T-1日成交量对比功能（成交量为沪市和深市成交量之和）
     * @return
     */
    @Override
    public R<Map> stockTradeVol4InnerMarket() {
        //1.获取T日和T-1日的开始时间和结束时间
        //1.1 获取最近股票有效交易时间点--T日时间范围
        DateTime lastDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTime4T = openDateTime.toDate();
        Date endTime4T=lastDateTime.toDate();
        //TODO  mock数据
        startTime4T=DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4T=DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.2 获取T-1日的区间范围
        //获取lastDateTime的上一个股票有效交易日
        DateTime preLastDateTime = DateTimeUtil.getPreviousTradingDay(lastDateTime);
        DateTime preOpenDateTime = DateTimeUtil.getOpenDate(preLastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTime4PreT = preOpenDateTime.toDate();
        Date endTime4PreT=preLastDateTime.toDate();
        //TODO  mock数据
        startTime4PreT=DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4PreT=DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.获取上证和深证的配置的大盘id
        //2.1 获取大盘的id集合
        List<String> markedIds = stockInfoConfig.getInner();
        //3.分别查询T日和T-1日的交易量数据，得到两个集合
        //3.1 查询T日大盘交易统计数据
        List<Map> data4T=stockMarketIndexInfoMapper.getStockTradeVol(markedIds,startTime4T,endTime4T);
        if (CollectionUtils.isEmpty(data4T)) {
            data4T=new ArrayList<>();
        }
        //3.2 查询T-1日大盘交易统计数据
        List<Map> data4PreT=stockMarketIndexInfoMapper.getStockTradeVol(markedIds,startTime4PreT,endTime4PreT);
        if (CollectionUtils.isEmpty(data4PreT)) {
            data4PreT=new ArrayList<>();
        }
        //4.组装响应数据
        HashMap<String, List> info = new HashMap<>();
        info.put("amtList",data4T);
        info.put("yesAmtList",data4PreT);
        //5.返回数据
        return R.ok(info);
    }

    /**
     * 查询当前时间下股票的涨跌幅度区间统计功能
     * 如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询点
     * @return
     */
    @Override
    public R<Map> getIncreaseRangeInfo() {
        //1.获取股票最新一次交易的时间点
        DateTime curDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // TODO mock data 等后续完成股票采集job工程，再将代码删除即可
        curDate = DateTime.parse("2021-12-28 13:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = curDate.toDate();
        //2.通过Mapper查询股票信息
        List<Map> maps = stockRtInfoMapper.getIncreaseRangeInfo(endDate);
        // 获取有序的涨幅区间元素转换成的Map对象
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        // 方式1：普通循环
//        List<Map> allMaps = new ArrayList<>();
//        for (String title : upDownRange) {
//            Map temp = null;
//            for (Map map : maps) {
//                if(map.containsValue(title)) {
//                    temp = map;
//                    break;
//                }
//            }
//            if(temp == null) {
//                temp = new HashMap<>();
//                temp.put("title", title);
//                temp.put("count", 0);
//            }
//            allMaps.add(temp);
//        }
        // 方案2：使用stream遍历获取
        List<Map> allMaps = upDownRange.stream().map(title -> {
            Optional<Map> result = maps.stream().filter(map -> map.containsValue(title)).findFirst();
            if(result.isPresent()) {
                return result.get();
            } else {
                HashMap<String, Object> temp = new HashMap<>();
                temp.put("title", title);
                temp.put("count", 0);
                return temp;
            }
        }).collect(Collectors.toList());
        //3.组装数据
        HashMap<Object, Object> mapInfo = new HashMap<>();
        mapInfo.put("time", curDate.toString("yyyy-MM-dd HH:mm:ss"));
        mapInfo.put("infos", allMaps);
        //4.返回数据
        return R.ok(mapInfo);
    }

    /**
     * 功能描述：查询单个个股的分时行情数据，也就是统计指定股票T日每分钟的交易数据；
     *         如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询时间点
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        // 1、获取最新开盘时间、当天结束时间
        DateTime curDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
        // TODO mock data 等后续完成股票采集job工程，再将代码删除即可
        curDate = DateTime.parse("2021-12-28 13:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = curDate.toDate();
        Date openDate = DateTimeUtil.getOpenDate(curDate).toDate();
        // 2、调用mapper层查询
        List<Stock4MinuteDomain> data = stockRtInfoMapper.getStock4MinuteInfo(openDate, endDate, stockCode);
        // 3、返回数据
        return R.ok(data);
    }

    /**
     * 单个个股日K 数据查询 ，可以根据时间区间查询数日的K线数据
     * @param stockCode 股票编码
     */
    @Override
    public R<List<Stock4EvrDayDomain>> stockCreenDkLine(String stockCode) {
        //1.1 获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = endDateTime.toDate();
        //TODO MOCKDATA
        endTime=DateTime.parse("2022-01-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取开始时间
        DateTime startDateTime = endDateTime.minusDays(10);
        Date startTime = startDateTime.toDate();
        //TODO MOCKDATA
        startTime=DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // 2、调用mapper层查询
        List<Stock4EvrDayDomain> data = stockRtInfoMapper.getStock4EvrDayInfo(startTime, endTime, stockCode);
        // 3、返回数据
        return R.ok(data);
    }
}
